#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sqlite3
import shutil
import json
from tqdm import tqdm

class MBTilesConverter:
    """
    将下载的瓦片转换为MBTiles格式
    不依赖外部库，纯SQLite实现
    """
    
    def __init__(self, tiles_dir, output_file, name="Offline Map", description="Downloaded Map Tiles"):
        """
        初始化转换器
        
        参数:
            tiles_dir: 瓦片所在目录
            output_file: 输出的MBTiles文件路径
            name: 地图名称
            description: 地图描述
        """
        self.tiles_dir = tiles_dir
        self.output_file = output_file
        self.name = name
        self.description = description
        
        # 确保输出目录存在
        output_dir = os.path.dirname(os.path.abspath(output_file))
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
    
    def get_tile_files(self):
        """
        获取所有瓦片文件
        
        返回:
            瓦片文件列表，每个元素为 (zoom, x, y, file_path)
        """
        tile_files = []
        
        # 遍历瓦片目录
        for zoom_dir in os.listdir(self.tiles_dir):
            zoom_path = os.path.join(self.tiles_dir, zoom_dir)
            if not os.path.isdir(zoom_path):
                continue
            
            try:
                zoom = int(zoom_dir)
            except ValueError:
                continue
            
            for x_dir in os.listdir(zoom_path):
                x_path = os.path.join(zoom_path, x_dir)
                if not os.path.isdir(x_path):
                    continue
                
                try:
                    x = int(x_dir)
                except ValueError:
                    continue
                
                for y_file in os.listdir(x_path):
                    # 支持多种瓦片格式: png 和 jpg/jpeg
                    if not (y_file.endswith('.png') or y_file.endswith('.jpg') or y_file.endswith('.jpeg')):
                        continue
                    
                    try:
                        y = int(os.path.splitext(y_file)[0])
                    except ValueError:
                        continue
                        
                    file_path = os.path.join(x_path, y_file)
                    
                    tile_files.append((zoom, x, y, file_path))
        
        return tile_files
    
    def create_mbtiles(self, tile_files):
        """
        创建MBTiles文件
        
        参数:
            tile_files: 瓦片文件列表，每个元素为 (zoom, x, y, file_path)
        """
        # 如果输出文件已存在，先删除
        if os.path.exists(self.output_file):
            os.remove(self.output_file)
        
        # 创建数据库连接
        conn = sqlite3.connect(self.output_file)
        cursor = conn.cursor()
        
        # 创建数据库表
        cursor.execute('''
        CREATE TABLE tiles (
            zoom_level INTEGER,
            tile_column INTEGER,
            tile_row INTEGER,
            tile_data BLOB
        )
        ''')
        
        cursor.execute('''
        CREATE TABLE metadata (
            name TEXT,
            value TEXT
        )
        ''')
        
        # 创建索引
        cursor.execute('''
        CREATE UNIQUE INDEX tile_index ON tiles (zoom_level, tile_column, tile_row)
        ''')
        
        # 检测主要的瓦片格式
        tile_format = "png"  # 默认格式
        if tile_files:
            # 检查第一个瓦片的格式
            first_tile = tile_files[0][3]
            if first_tile.endswith('.jpg') or first_tile.endswith('.jpeg'):
                tile_format = "jpg"
        
        # 添加元数据
        metadata = {
            "name": self.name,
            "description": self.description,
            "type": "baselayer",
            "version": "1.0.0",
            "format": tile_format,
            "minzoom": min(t[0] for t in tile_files) if tile_files else 0,
            "maxzoom": max(t[0] for t in tile_files) if tile_files else 0
        }
        
        for name, value in metadata.items():
            cursor.execute("INSERT INTO metadata VALUES (?, ?)", (name, str(value)))
        
        # 添加瓦片数据
        for zoom, x, y, file_path in tqdm(tile_files, desc="导入瓦片", unit="瓦片"):
            # MBTiles使用TMS坐标系，需要转换Y坐标
            tms_y = (2 ** zoom - 1) - y
            
            with open(file_path, 'rb') as f:
                tile_data = f.read()
            
            cursor.execute(
                "INSERT INTO tiles VALUES (?, ?, ?, ?)",
                (zoom, x, tms_y, sqlite3.Binary(tile_data))
            )
        
        # 提交更改并关闭连接
        conn.commit()
        conn.close()
        
        print(f"转换完成: {len(tile_files)} 个瓦片已导入 {self.output_file}")
    
    def convert(self):
        """
        执行转换过程
        
        返回:
            成功转换的瓦片数量
        """
        try:
            # 获取所有瓦片文件
            tile_files = self.get_tile_files()
            
            if not tile_files:
                print(f"错误: 在 {self.tiles_dir} 中未找到任何瓦片")
                return 0
            
            # 创建MBTiles文件
            self.create_mbtiles(tile_files)
            
            return len(tile_files)
        except Exception as e:
            print(f"转换过程中出错: {str(e)}")
            import traceback
            print(traceback.format_exc())
            return 0


if __name__ == "__main__":
    # 示例用法
    converter = MBTilesConverter(
        tiles_dir="./tiles",
        output_file="./output.mbtiles",
        name="浙江舟山",
        description="浙江舟山海域地图"
    )
    converter.convert() 